<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<script src="js/vue.js"></script>
	<title>计算器</title>
	<style>
		* {
			margin: 0;
			padding: 0
		}

		#app {
			max-width: 320px;
			margin: 0 auto;
			padding: 20px;
			border: 1px solid #000000;
			border-radius: 10px;
			background-color: #ddd;
			user-select: none;
			box-shadow: dimgray 5px 5px 2px;
		}

		.result {
			height: 35px;
			width: 144px;
			margin-bottom: 10px;
			text-align: right;
			padding: 5px;
			border: 2px solid #000000;
			border-radius: 5px;
			background-color: #dfdfdf;
			box-shadow: dimgray 2px 2px;
			text-shadow: dimgray 1px 1px 1px;
			font-size: 25px;
		}

		.re_out{
			color: #55f;
		}

		.btn {
			width: 50px;
			height: 50px;
			margin: 5px;
			font-size: 20px;
			box-shadow: dimgray 2px 2px;
			text-shadow: dimgray 1px 1px 1px;
		}

		.opr{
			background: #aaa;
		}

		.num{
			background: #ccc;
		}

		.btn-clear {
			background-color: #f99;
		}

		.calc {
			background-color: #9f9;
		}

		.btn:hover {
			background-color: white;
		}

		.del{
			background: #ff9;
		}
	</style>
</head>
<body>
<div id="app">
	<label for="re_in"></label><input ref="inputB" @keydown.enter="calcF()" v-model="output" class="result" id="re_in">
	<label><input readonly v-model="outputC" class="result re_out"></label>
	<div>
		<button class="btn num" @click="onclickF('7')">7</button>
		<button class="btn num" @click="onclickF('8')">8</button>
		<button class="btn num" @click="onclickF('9')">9</button>
		<button class="btn opr" @click="onclickF('+')">+</button>
		<button class="btn opr del" @click="del">del</button>
	</div>
	<div>
		<button class="btn num" @click="onclickF('4')">4</button>
		<button class="btn num" @click="onclickF('5')">5</button>
		<button class="btn num" @click="onclickF('6')">6</button>
		<button class="btn opr" @click="onclickF('-')">-</button>
		<button class="btn opr" @click="onclickF('^')">^</button>
	</div>
	<div>
		<button class="btn num" @click="onclickF('1')">1</button>
		<button class="btn num" @click="onclickF('2')">2</button>
		<button class="btn num" @click="onclickF('3')">3</button>
		<button class="btn opr" @click="onclickF('*')">*</button>
		<button class="btn opr" @click="onclickF('%')">%</button>
	</div>
	<div>
		<button class="btn num" @click="onclickF('0')">0</button>
		<button class="btn calc" @click="calcF">=</button>
		<button class="btn num" @click="onclickF('.')">.</button>
		<button class="btn opr" @click="onclickF('/')">/</button>
		<button class="btn btn-clear" @click="resetF">C</button>
	</div>
</div>
<script>
	new Vue({
		el: '#app',
		data: {
			'output': '',
			'output1': ''
		},
		mounted() {
			this.$refs.inputB.focus()
		},
		methods: {
			onclickF(str_input) {
				this.output += str_input //根据按钮添加文本字符
			},
			del() {
				this.output += ''//未知计算后无法删除结果字符串，添加这个得以删除
				this.output = this.output.slice(0, -1)//删除显示的文本
			},
			calcF() {
				const nums = [];//存储数字
				const operators = [];//存储运算符
				const precedence = {'+': 1, '-': 1, '%': 2, '*': 3, '/': 3, '^': 4};//设置运算优先级
				this.output = this.output.replace(/\.0+$|\D$/g,'')//移除结尾小数点结尾的0或结尾的运算符
				function performOperation() {
					const operator = operators.pop();
					const operand2 = nums.pop();
					const operand1 = nums.pop();
					switch (operator) {
						case '+':
							nums.push(operand1 + operand2);
							break
						case '-':
							nums.push(operand1 - operand2);
							break
						case '%':
							nums.push(operand1 % operand2);
							break
						case '*':
							nums.push(operand1 * operand2);
							break
						case '/':
							nums.push(operand1 / operand2);
							break
						case '^':
							nums.push(operand1 ** operand2);
							break
						default:
							break;
					}
				}

				if (this.output[0] === '-') {
					this.output = '0' + this.output
				}
				for (let i = 0; i < this.output.length; i++) {
					let char = this.output[i];
					if (!isNaN(char)) {
						let number = '';
						while (!isNaN(char) || char === '.') {
							number += char;
							char = this.output[++i];
						}
						nums.push(parseFloat(number));
						i--;
					} else {
						while (operators.length > 0 && precedence[char] <= precedence[operators[operators.length - 1]]) {
							performOperation();
						}
						operators.push(char);
					}
				}
				while (operators.length > 0) {
					performOperation();
				}
				this.output1 = nums[0]
				if (this.output[0] === '0' && this.output.length > 1) {
					this.output = this.output.replace(this.output[0], '')
				}
			},
			resetF() {
				this.output = ''
			}
		},
		watch: {
			output() {//在这里监听输入，如果输入不符合运算的字符，则自动删除
				if (this.output.includes('=')) {//允许键盘输入等号计算
					this.output = this.output.replace("=", '')
					this.calcF()
				} else {
					const regex = /[^0-9+\-*/^.%]/g;
					this.output = this.output.replace(regex, '')
						.replace(/\D(\D)/g, '$1')//不允许连续的运算符，比如1+-3,4\+*
						.replace(/^0(\d)/g, '$1')//不允许开头数字0连续
						.replace(/([^0-9.])0(\d)/g, '$1$2')//不允许运算符后面0紧跟其他数字
						.replace(/\.0+(\D)/g, '$1')//把整数的小数点去掉
						.replace(/(\d+\.\d+)\./g, '$1')//只允许小数点在连续的数字中出现一次
						.replace(/^[^0-9\-]/g, '')//只允许数字和负号开头
				}
			}
		},
		computed: {
			outputC() {
				return this.output1
			}
		}
	})
</script>
</body>
</html>